package com.summer.campussct.interceptor;

import cn.hutool.json.JSONUtil;
import com.summer.campussct.annotation.Permission;
import com.summer.campussct.pojo.dto.PermissionTuple;
import com.summer.campussct.pojo.dto.RestResult;
import com.summer.campussct.pojo.dto.UserIdWithPermList;
import com.summer.campussct.utils.JwtUtil;
import com.summer.campussct.utils.UserIdHolder;
import io.jsonwebtoken.Claims;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;

@Component
public class AuthenticationInterceptor implements HandlerInterceptor {

    @Resource
    private JwtUtil jwtUtil;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1. 如果访问的是受限资源，则进行解析令牌，否则直接放行
        Method method = ((HandlerMethod) handler).getMethod();
        Permission annotation = method.getAnnotation(Permission.class);
        if (annotation != null){
            // 解析令牌，存入threadLocal
            // 1. 获取请求头中的jwt，若没携带jwt则返回401
            String jwt = request.getHeader("Authorization");
            if (jwt == null || "".equals(jwt)){
                forbidden(response, HttpServletResponse.SC_UNAUTHORIZED, "请先登录");
                return false;
            }
            // 2. 解析jwt
            Claims claims = null;
            try {
                claims = jwtUtil.parseJwt(jwt);
            } catch (Exception e) {
                forbidden(response, HttpServletResponse.SC_UNAUTHORIZED, "无效token");
                return false;
            }
            String userIdWithAuthJson = claims.getSubject();
            UserIdWithPermList userIdWithAuthDto = JSONUtil.toBean(userIdWithAuthJson, UserIdWithPermList.class);
            Long userId = userIdWithAuthDto.getUserId();
//            List<String> authList = userIdWithAuthDto.getPermList();
            List<PermissionTuple> permissionTupleList = userIdWithAuthDto.getPermissionTupleList();

            // 3. 将userid存入ThreadLocal中
            UserIdHolder.saveId(userId);

            // 没有权限则返回403
            // 如果此接口为登录权限则放行（因为每个登录用户都具有登陆权限）
            if (annotation.value().equals("login")){
                return true;
            }
            // 如果为其他权限则需要检查
            for (PermissionTuple permissionTuple : permissionTupleList) {
                // 判断是否有权限
                if (permissionTuple.getPermCode().equals(annotation.value())){
                    // 判断是否具有对应权限范围
                    if ((annotation.range() & permissionTuple.getPermRange()) != 0){
                        return true;
                    }else {
                        // 没有对应权限范围
                        forbidden(response, HttpServletResponse.SC_FORBIDDEN, "权限不足");
                        return false;
                    }
                }
            }
            //走到这里表示没有对应权限
            forbidden(response, HttpServletResponse.SC_FORBIDDEN, "权限不足");
            return false;
//            if (!authList.contains(annotation.value())){
//                forbidden(response, HttpServletResponse.SC_FORBIDDEN, "权限不足");
//                return false;
//            }
        }
        return true;
    }

    private void forbidden(HttpServletResponse response, int status, String msg) throws IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        response.setStatus(status); // 设置403状态码
        response.getWriter().write(JSONUtil.toJsonStr(RestResult.error(msg))); // 返回错误信息
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        UserIdHolder.removeId();
    }
}
